/*
 * File:   DivideAndConquer.h
 * Author: jd219546
 *
 * Created on 17 octobre 2011, 18:02
 */

#ifndef DIVIDEANDCONQUER_H
#define	DIVIDEANDCONQUER_H

#include "CentralRowSolver.h"
#include "CentralColumnSolver.h"
#include "Result.h"
#include "Data.h"

#include "Kadane.h"

class Command
{
    public:
    Command(){}
    virtual ~Command(){}
    Command(const s_rect & rect) : rect(rect), workload((rect.x1 - rect.x0)*(rect.y1 - rect.y0))
    {
    }
        virtual Result solve_MCS(const Data & data) = 0;
        virtual string name() const = 0;

    protected:
            s_rect rect;
            Result res;
            public:
                            t_int workload;
};

class KadaneCommand : public Command
{
    public:
        KadaneCommand(const s_rect & rect):Command(rect)
        {
        }
        Result solve_MCS(const Data & data)
        {
            Kadane::kadane2DBlock(data,res,rect);
            return res;
        }
        virtual string name() const{return string("Kadane");}

};

class CentralCommand : public Command
{
    public:
        CentralCommand(const s_rect & rect, const t_int & central):Command(rect),central(central)
        {
        }
        virtual Result solve_MCS(const Data & data) = 0;
    protected:
        t_int central;
};

class CentralRowCommand : public CentralCommand
{
    public:
    CentralRowCommand(const s_rect & rect, const t_int & central):CentralCommand(rect,central)
    {
    }
    Result solve_MCS(const Data & data)
    {
        central_solver.solve_MCS(&data, res, this->rect, this->central);
        return res;
    }
    virtual string name() const{return string("CentralRow");}
    private:
        CentralRowSolver central_solver;
};

class CentralColCommand : public CentralCommand
{
    public:
    CentralColCommand(const s_rect & rect, const t_int & central):CentralCommand(rect,central)
    {
    }
    Result solve_MCS(const Data & data)
    {
        central_solver.solve_MCS(&data, res, this->rect, this->central);
        return res;
    }
    virtual string name() const{return string("CentralColumn");}
    private:
        CentralColumnSolver central_solver;
};

class DivideAndConquer {
public:
    DivideAndConquer(int max_recursivity);
    virtual ~DivideAndConquer();

    void solve_MCS(const Data& data, Result & result) ;
private:
    void update_result(Result & result, t_int x0, t_int y0, t_int x1, t_int y1, t_int sum);
    const Data * data_ptr;
    void recursive_divide_and_conquer( int recursivity_level, s_rect rect);
    int max_recursivity;
    void solve_local_MCS(Result & result, s_rect rect) ;
    CentralRowSolver central_row_solver;
    CentralColumnSolver central_col_solver;
    vector< Result > each_thread_result;
    vector< Command *> command_queue;

};



#endif	/* DIVIDEANDCONQUER_H */

